unit uFormMain;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  StdCtrls;

type

  { TFormMain }

  TFormMain = class(TForm)
    btAccessViolation: TButton;
    btCreateThread: TButton;
    btOutputDebugString: TButton;
    btInt3_cc: TButton;
    btExitProcess: TButton;
    btInt3_cd03: TButton;
    btPrivInstr: TButton;
    btCreateProcess: TButton;
    edDebugString: TEdit;
    edExitProcessCode: TEdit;
    edCreateProcessResult: TEdit;
    edThread: TEdit;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    mmCmdLine: TMemo;
    procedure btAccessViolationClick(Sender: TObject);
    procedure btCreateProcessClick(Sender: TObject);
    procedure btCreateThreadClick(Sender: TObject);
    procedure btExitProcessClick(Sender: TObject);
    procedure btInt3_ccClick(Sender: TObject);
    procedure btInt3_cd03Click(Sender: TObject);
    procedure btOutputDebugStringClick(Sender: TObject);
    procedure btPrivInstrClick(Sender: TObject);
    procedure edDebugStringKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  FormMain: TFormMain;

implementation

uses
  Windows;

{$asmmode intel}
{$R *.lfm}

procedure CodeSample;
var
  a, b, c: integer;
begin
  a := 5;
  b := 10;
  c := a + b;
end;

{ TFormMain }

procedure TFormMain.btAccessViolationClick(Sender: TObject);
begin
  PInteger(123)^ := 456;
end;

procedure TFormMain.btCreateProcessClick(Sender: TObject);
var
  sinf: TStartupInfo;
  pinf: TProcessInformation;
begin
  ZeroMemory(@sinf, sizeof(sinf));
  sinf.cb := sizeof(sinf);
  CreateProcess(PChar(ParamStr(0)), nil, nil, nil, false, 0, nil, nil, sinf, pinf);
  edCreateProcessResult.Text := SysErrorMessageUTF8(GetLastError);
end;

var
  hThread: THANDLE;

function Thread1(lpParameter: LPVOID): DWORD; stdcall;
begin
  result := 123;
end;

procedure TFormMain.btCreateThreadClick(Sender: TObject);
var
  id: DWORD;
begin
  id := 0;
  hThread := CreateThread(nil, 0, @Thread1, nil, 0, id);
  edThread.Caption := Format('id: %d; handle: %d', [id, hThread]);
end;

procedure TFormMain.btExitProcessClick(Sender: TObject);
var
  code: integer;
begin
  if not TryStrToInt(edExitProcessCode.Text, code) then
    code := 0;
  ExitProcess(code);
end;

procedure TFormMain.btInt3_ccClick(Sender: TObject);
begin
  asm
    int 3
  end;
end;

procedure TFormMain.btInt3_cd03Click(Sender: TObject);
begin
  asm
    db $cd, $03
  end;
end;

procedure TFormMain.btOutputDebugStringClick(Sender: TObject);
begin
  Windows.OutputDebugStringA(PAnsiChar(edDebugString.Text));
end;

procedure TFormMain.btPrivInstrClick(Sender: TObject);
begin
  asm
    sti
  end;
end;

procedure TFormMain.edDebugStringKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    VK_RETURN:
      btOutputDebugStringClick(nil);
  end;
end;

procedure TFormMain.FormCreate(Sender: TObject);
begin
  Left := 0;
  Top := 0;

  mmCmdLine.Text := GetCommandLine;

  CodeSample;
end;

end.

